It All Began with COM (and DCOM)
COM helped encapsulate
object-oriented systems into binary components. It supported
encapsulation by preventing leakage of implementation details, and
logic encapsulated in COM components could only be accessed if it had
been exposed via a public interface. DCOM extended COM to enable
communication across different computers, as shown in Figure 1.
DCOM established a
secure remote protocol that leverages the security framework provided
by the native Windows operating system. For example, it used Access
Control Lists (ACL) to secure components that could then be configured
using the DCOMCNFG tool.
DCOM
had several disadvantages, including the use of “keep-alive” pinging
(also known as distributed garbage collection), which required that the
client periodically ping distributed objects. If the distributed object
did not receive a message for a specified duration of time, it was
deactivated and eventually destroyed. Distributed garbage collection
was error-prone, increased network traffic, and did not scale well
beyond local networks. DCOM was therefore not suitable for WANs.
Furthermore, DCOM
communicated via live TCP connections over specific ports, which made
it complex to configure across multiple computers and firewalls, and
even less suitable for communication over the Internet.
COM+ Services
COM+ services extended
COM by providing services with increased scalability and throughput
that could individually host COM components. The out-of-the-box
services provided by COM+ included object pooling, just-in-time
activation, constructor string configuration, synchronization,
security, queued components, loosely coupled events, and several
others. Table 1 provides a list of primary COM+ services.
Table 1. A list of available COM+ services.
COM+ Service | Description |
---|
transactions | supported distributed transactions across multiple databases, including databases from other vendors |
queued components | provided
an easy way to invoke and execute components asynchronously and allowed
processing to occur regardless of the availability or accessibility of
either the sender or the receiver |
loosely coupled events | provided support for late-bound events (essentially the plumbing code to implement publish-and-subscribe systems) |
just-in-time activation (JITA) | could be configured to handle just-in-time activation necessary for smart client access |
synchronization | multithreaded COM+ components could use synchronization locks |
security | provided a role-based security model and a supporting programming model |
role-based security | provided
a mechanism to define roles for applications and the ability to
authorize applications (at the component, interface, or method levels)
based on those roles |
private components | provided
a mechanism to mark a component as private (which meant it could be
seen and activated only by other components in the same application) |
SOAP service | allowed an existing component to be published as a SOAP-based Web service |
With the release of Windows XP,
a new version of the COM+ services emerged. COM+ version 1.5 enhanced
existing COM+ services and introduced additional services, including:
configurable isolation level (in COM+ 1.0, “SERIALIZABLE” was the only isolation level allowed for transactions)
applications could be run as Windows services
memory
gates were introduced, which prevented objects from being constructed
if the free memory in the system fell below a certain threshold
COM+
components could be used more than once (typically, helper components
or shared components needed to be shared across COM+ applications)
.NET Assemblies
A .NET assembly was a set of files
containing classes, metadata, and executable code. An assembly was the
smallest versionable, installable unit in .NET. It contained a manifest
that stored metadata describing the classes and how these classes
related to one another. The runtime read this manifest to obtain
information about the contents of the assembly. The manifest could
further contain references to other assemblies it depended on. Unlike
unmanaged COM+ components, .NET assemblies could be deployed by simply
being copied to the target machine.
.NET assemblies could be
classified as either private or shared. Private assemblies were used by
a single application, whereas shared assemblies could be accessed by
multiple applications on the same machine. .NET allowed several
versions of the same assembly to be installed, thereby eliminating many
problems that existed previously with sharing unmanaged COM+ components
between applications. This flexibility helped alleviate the “DLL hell”
problem that haunted the COM+ world before .NET was introduced.
Distributed Transaction Coordinator
With transactions, a group
of related actions occurs as a single, atomic unit. If all actions
complete successfully inside a transaction, the transaction is
committed and the updated data is written permanently. If any of the
actions fail, all actions are rolled back. Distributed transactions are
based on the two-phase commit protocol, which consists of a “prepare”
phase and a “commit” phase. During the prepare phase, all participants
in the transaction must agree to complete the actions successfully. If
a participant aborts, all the other participants in the transaction
will roll back any changes made up until that point. If the prepare
phase is successful across all participants in the transaction, the
commit phase is started and data is permanently affected across all
systems.
|
.NET
Enterprise Services supported distributed transactions, wherein a given
transaction could span multiple databases. As shown in Figure 4.4,
the two-phase commit is coordinated by a transaction manager. In
Enterprise Services, the Distributed Transaction Coordinator (DTC)
plays the role of a transaction manager (based on the X/Open XA
industry standard).
When .NET first arrived, it
did not provide its own component technology but relied on COM+
services and built upon the COM+ infrastructure. COM+ services could be
accessed from both managed and unmanaged code. The programming model to
access COM+ services in .NET was simplified with .NET Enterprise
Services.
.NET used classes residing in the System.EnterpriseServices
namespace to access COM+ services. A .NET component that used COM+
services was called a “serviced” component. To take advantage of COM+
services, a .NET class had to be derived from the base class ServicedComponent.
Example 1 represents a simple scenario involving a transaction, where the GreetCaller method updates multiple databases with the caller’s name and returns a greeting message to the caller.
Example 1.
using System; using System.Collections.Generic; using System.Text; using System.EnterpriseServices; [assembly: ApplicationName("GreetingComponent")] [assembly: AssemblyKeyFileAttribute("Greeting.snk")] namespace Greetings{ [Transaction(TransactionOption.Required)] [ObjectPooling(MinPoolSize = 2, MaxPoolSize = 50)] [JustInTimeActivation] public class Greetings : ServicedComponent { [AutoComplete] public string GreetCaller(string callerName) { return "Hello " + callerName; } protected override bool CanBePooled() { return true; } } }
|
Here’s a quick overview of what this code sample accomplishes.
The Greetings
class is enabled to use transactions using the Transaction attribute
and AutoComplete attribute. When the AutoComplete attribute is used,
SetComplete() or SetAbort() are not to be called. If an exception is thrown in a transaction, SetAbort()
is called automatically and if no exception occurs, SetComplete() is
called automatically. The CanBePooled() method is overridden and set to
return true to enable object-pooling. Since just-in-time activation is
also used, the Dispose() function is never called. The object is
deactivated, but not destroyed.
.NET Enterprise Services and Service-Orientation
.NET Enterprise Services
imposed some limitations when it came to service design. For example,
communication was dependent on DCOM and the client proxy was tightly coupled
to the server. This made it difficult to fully apply the Standardized
Service Contract and Service Loose Coupling principles and further
inhibited one of the primary objectives of
service-oriented computing, which is to increase options for exploring
vendor diversity.